import paramiko, time, os, locale, warnings, re

from scp import SCPClient
# from .util import # logger, CfgParser

sys_pre_encoding = locale.getpreferredencoding()
warnings.filterwarnings('ignore')

class RemoteCtrl:
    def __del__(self):
        '''
            注: RemoteCtrl(远端连接)内的被调用方法, 使用者不会用到, 且不用理会
        '''
        self.delete_session()

    def __init__(self):
        # cfg = CfgParser().parse_config()

        self.host = cfg['ssh.host']
        self.user = cfg['ssh.user']
        self.password = cfg['ssh.password']
        self.port = int(cfg['ssh.ssh_port'])
        self.timeout = int(cfg['ssh.timeout'])
        self.ssh_session = []
   

    def check_session(self, index):
        if len(self.ssh_session) == 0:
            # logger.error("Session not found......")
            raise Exception("Session not found......")

        return isinstance(index, int) and index < len(self.ssh_session)


    def create_SSHSession(self, host=None, user=None, password=None, port=None):
        '''
            功能: 创建SSH会话, 连接SHH

            参数:
                host: Linux的IP地址(可选填), 默认调用配置文件(config.cfg -> [SSH])的值
                user: 登录Linux端的用户名(可选填), 默认调用配置文件(config.cfg -> [SSH])的值
                password: 登录Linux端的密码(可选填), 默认调用配置文件(config.cfg -> [SSH])的值
                port: 登录Linux端的端口号(可选填), 默认调用配置文件(config.cfg -> [SSH])的值
        '''
        user = self.user if user is None else user
        password = self.password if password is None else password
        host = self.host if host is None else host
        port = int(self.port) if port is None else 22

        client = paramiko.SSHClient()
        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        client.connect(hostname=host, username=user, password=password, port=port)
        # logger.info("Connecting to SSH on ip: {0} user:{1} pwd:{2} ...".format(host, user, password))

        self.ssh_session.append(client)
        return client


    def delete_session(self, index=None):
        '''
            注: RemoteCtrl(远端连接)内的被调用方法, 使用者不会用到, 且不用理会
        '''
        if index is not None:
            self.ssh_session[index].close()
            # del self.ssh_session[index]

        else:
            for session in self.ssh_session:
                session.close()
            
            self.ssh_session = []

        # logger.info("Delete SSH session success ...")


    def send_cmd_by_ssh(self, command="", raise_error=False, index=None):
        '''
            功能: SSH发Linux命令操作

            参数: 
                command: 要发的linux命令, 默认为 ""
                raise_error: 是否选择抛出错误操作(可选填), 默认为False, 抛错可设置raise_error=True
        '''
        client = self.ssh_session[index] if self.check_session(index) else self.ssh_session[-1]
        result = ''
        channel = None
        try:
            channel = client.invoke_shell()

            # logger.info("Opening the Shell Terminal ... \n")
            time.sleep(2)

            status = channel.recv(9999).decode("utf8")
            if 'SMASHLITE Scorpio Console' in status:
                time_out = self.timeout

                channel.send(command + '\n')
                result = channel.recv(9999).decode("utf8")
                output_check = re.search(r'COMMAND COMPLETED', result)
                
                while not output_check:
                    time.sleep(1)
                    result = channel.recv(9999).decode("utf8")
                    output_check = re.search(r'COMMAND COMPLETED', result)
                    time_out -= 1
                    if time_out < 0:
                        raise Exception("Error : Timeout!!!")
                    
                # logger.info("Run Command {0}, Result: \n{1}".format(command, result.strip()))
                # channel.send('exit\n')

            else:
                stdin, stdout, stderr = client.exec_command(command)
                result = stdout.read().decode(sys_pre_encoding)
                erroutput = stderr.read().decode(sys_pre_encoding)
                
                # logger.info("Run Command {0}, Result: \n{1}".format(command, result.strip()))

            if not result and erroutput:
                result = erroutput
                msg = "Stdout is null or an error occurred: \n {0} ".format(erroutput)
                
                # logger.error(msg)     
                raise Exception("Stdout is null or an error occurred...")    

            # logger.info("All command has execute success ...") 
            return result

        except Exception as err:
            result = err
            msg = "SSH Process failed ... \n Error:{0}".format(err)
            
            # logger.error(msg)
            if raise_error:
                raise Exception(err)

        finally:
            # self.__del__()
            return result
        
        
    def SCP(self, operation, remote_dir, local_dir, raise_error=False, index=None):
        '''
            功能: 远程文件拷贝

            参数: 
                operation: 要执行的scp操作, 可设置值 download(上传)或其他值(下载)

                remote_dir: 远端文件路径, 地址必须为绝对路径

                local_dir: 本地文件路径, 地址必须为绝对路径

                raise_error: 是否选择抛出错误操作(可选填), 默认为False, 抛错可设置 raise_error=True
        '''
        operation = operation.lower()
        client = self.ssh_session[index] if self.check_session(index) else self.ssh_session[-1]
        try:
            scp_client = SCPClient(client.get_transport(), socket_timeout=self.timeout)

            if 'download' == operation:
                scp_client.get(remote_dir, local_dir, recursive=True)
                # logger.info('SCP Downloading {0}, from {1}(remote direction) to {2}(local direction) ...'.format(os.path.split(remote_dir)[1], remote_dir, local_dir))
            else:
                scp_client.put(local_dir, remote_dir, recursive=True)
                # logger.info('SCP Uploading {0}, from {1}(local direction) to {2}(remote direction) ...'.format(os.path.split(local_dir)[1], local_dir, remote_dir))

            # logger.info('Execute SCP command over ...')
            return True

        except Exception as err:
            msg = 'SSH/SCP has exceptions ... \n Error: {0}'.format(err)
            # logger.error(msg)
            if raise_error:
                raise Exception(err)

        finally:
            self.__del__()
            
        return False
        